<template>
	<template
		v-if="linkOnly"
	>
		<a 
            :class="[
                'app-editor-container',
                'app-data-picker',
                `app-data-picker-${name}`,
            ]"
            @click="openLinkView">
            {{ value }}
        </a>
	</template>
	<template v-else-if="isAC && !isDropdown">
		<a-auto-complete
			:class="[
				'app-editor-container',
				'app-data-picker',
				`app-data-picker-${name}`,
			]"
			ref="autoComRef"
			:value="currentVal"
			:options="items"
			:open="open"
			:disabled="disabled || readonly"
			dropdownClassName="app-editor-data-picker-dropdown"
            @dropdownVisibleChange="handleVisibleChange"
			@search="onSearch"
			@focus="onFocus"
			@blur="onBlur"
		>
			<template #option="option">
				<a-empty v-if="option.noData" :image="simpleImage" />
				<div v-else @click="onSelect(option[deKeyField])">
					{{ option[deMajorField] }}
				</div>
			</template>
			<a-input :placeholder="placeholder">
				<template #suffix>
					<CloseCircleOutlined
						v-show="value"
						class="suffix-icon"
						@click="clear"
					/>
					<DownOutlined
						v-show="!open"
						class="suffix-icon"
					/>
					<UpOutlined v-show="open" class="suffix-icon" />
					<SearchOutlined
						v-if="showPickUpView && showButton"
						class="suffix-icon"
						@click="openView"
					/>
					<ExportOutlined
						v-if="showLinkView"
						class="suffix-icon"
						@click="openLinkView"
					/>
				</template>
			</a-input>
		</a-auto-complete>
	</template>
	<template v-else-if="!isAC">
		<a-input
			:class="[
				'app-editor-container',
				'app-data-picker',
				`app-data-picker-${name}`,
			]"
			:value="value"
			:placeholder="placeholder"
			@focus="($event:any)=>{onFocusBlurEmit('focus',$event)}"
			@blur="($event:any)=>{onFocusBlurEmit('blur',$event)}"
		>
			<template #suffix>
				<CloseCircleOutlined
					v-show="value"
					class="suffix-icon"
					@click="clear"
				/>
				<SearchOutlined
					v-if="showPickUpView && showButton"
					class="certain-category-icon"
					@click="openView"
				/>
				<LinkOutlined v-if="showLinkView" @click="openLinkView" />
			</template>
		</a-input>
	</template>
	<template v-else-if="isDropdown">
		<a-select
            ref="dataPicker"
			:class="[
				'app-editor-container',
				'app-data-picker',
				`app-data-picker-${name}`,
			]"
			showArrow
			:showSearch="false"
			:mode="multiple ? 'multiple' : 'tag'"
			:value="currentVal"
			:disabled="disabled"
			:filterOption="false"
			@change="onChange"
			@focus="onFocus"
			@blur="onBlur"
			@dropdownVisibleChange="handleVisibleChange"
			:placeholder="placeholder"
		>
			<template #suffixIcon>
				<span class="app-data-picker-dropdown-select-icon">
                    <CloseCircleOutlined
						v-show="value"
						class="suffix-icon"
						@click="clear"
					/>
					<SearchOutlined
						v-if="showPickUpView && showButton"
						class="certain-category-icon"
						@click="openView"
					/>
					<LinkOutlined v-if="showLinkView" @click="openLinkView" />
				</span>
			</template>
			<a-select-option
				v-for="(item, index) in items"
				:key="index"
				:value="item[deKeyField]"
			>
				{{ item[deMajorField] }}
			</a-select-option>
		</a-select>
	</template>
</template>

<script setup lang="ts">
import { Ref, ref } from 'vue';
import { Empty } from 'ant-design-vue';
import {
	SearchOutlined,
	ExportOutlined,
	CloseCircleOutlined,
	DownOutlined,
	UpOutlined,
	LinkOutlined,
} from '@ant-design/icons-vue';
import { IParam, IEvent, computedNavData } from '@/core';
import { dataPickerProps } from './data-picker';
import { handleEditorNavParams, useEditorTypeParams, searchEntityData } from '@/hooks/use-editor';
import { deepCopy, isExistAndNotEmpty } from '@/core/utils';
// 外部数据选择编辑器（一般应用外键数据的录入），支持AC或数据选择的方式进行录入，数据选择编辑器需要额外的值项属性存储实际的值，自身只存储显示内容。
// 数据选择编辑器提供多种形式，有能输入能选择、只能输入不能选择的或是只能选择的，另外为方便快速查看引用的数据，还提供了数据链接功能，可直接打开引用数据的相关视图(单选)
// 邮件地址输入控件，一般应用于类似邮件地址输入场景，用户可直接输入（提供AC支持）或是从外部数据中选择输入（多选）
interface EditorEmit {
	(name: 'component-action', value: IEvent<string>): void;
}
const props = defineProps(dataPickerProps);
const emit = defineEmits<EditorEmit>();
const { navContext, navViewParam } = handleEditorNavParams(props);
/**
 * 下拉数据集
 */
let items: Ref<any[]> = ref([]);
/**
 * 搜索值
 */
let searchVal: any = ref(undefined);
/**
 * 搜索状态
 */
let isSearch = ref(false);
/**
 * 下拉展开状态
 */
let open = ref(false);
/**
 * dataPicker引用
 */
const dataPicker: any = ref(null);
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
/**
 * 数据类型校验
 */
const { validateConfig, valueType, valueSeparator, objectNameField, objectIdField, objectValueField } = useEditorTypeParams();
validateConfig();
const compAttrs: IParam = useAttrs();
const autoComRef = ref();
/**
 * 显示选择视图
 */
const showPickUpView = computed(() => {
    return compAttrs.PICKUPVIEW == 'TRUE'
})
/**
 * 显示连接视图
 */
const showLinkView = computed(() => {
    return compAttrs.LINKVIEW == 'TRUE'
})
/**
 * 主信息属性，在valueType 为 OBJECTS 或 OBJECT 时识别 objectNameField
 */
const deMajorField: string = (valueType == 'OBJECTS' || valueType == 'OBJECT') && objectNameField ? objectNameField : props.deMajorField;
/**
 * 主键属性，在valueType 为 OBJECTS 或 OBJECT 时识别 objectIdField，valueType为 SIMPLE 且存在 objectIdField 为表单项过滤模式
 */
const deKeyField: string = (valueType == 'OBJECTS' || valueType == 'OBJECT' || valueType == 'SIMPLE' || !valueType) && objectIdField ? objectIdField : props.deKeyField;
/**
 * 当前值
 */
let currentVal: Ref<any> = computed(() => {
    let curValue: any;
    try {
        if (props.value) {
            let selects: IParam[] = [];
            if (props.multiple) {
                curValue = [];
                if (valueType == 'OBJECTS') {
                    selects = [...(props.value as any[])];
                } else {
                    if (objectIdField) {
                        let values = (props.value as string).split(valueSeparator ? valueSeparator : ',');
                        values.forEach((value: string) => {
                            selects.push({
                                [deKeyField]: value,
                            })
                        })
                    } else {
                        selects = JSON.parse((props.value as string));
                    }
                }
                selects.forEach((select: IParam) => {
                    curValue.push(select[deKeyField])
                })
            } else {
                if (valueType == 'OBJECT') {
                    selects.push({
                        [deKeyField]: props.data[props.valueItem],
                        [deMajorField]: (props.value as any)[deMajorField],
                    })
                } else {
                    selects.push({
                        [deKeyField]: props.data[props.valueItem],
                        [deMajorField]: props.value,
                    })
                }
                if (isSearch.value) {
                    curValue = searchVal.value
                } else {
                    curValue = selects[0][deMajorField]
                }
            }
            selects.forEach((select: IParam) => {
                const item = items.value.find((item: IParam) => Object.is(select[deKeyField], item[deKeyField]));
                if (!item && select[deKeyField]) {
                    items.value.push(select)
                }
            })
        }
    } catch (error) {
        console.log(error);
    }
    return curValue;
});

/**
 * @description 填充外键值附加数据
 * @param item 选中数据
 */
const fillPickUpData = (item: IParam) => {
	if (props.pickUpData) {
		let pickUpDataArray: string[] = props.pickUpData.split(';');
		if (pickUpDataArray && pickUpDataArray.length > 0) {
			for (let i = 0; i < pickUpDataArray.length; i++) {
				if (item) {
					emit('component-action', {
						name: pickUpDataArray[i],
						action: 'valueChange',
						data: item[pickUpDataArray[i]],
					});
				} else {
					emit('component-action', {
						name: pickUpDataArray[i],
						action: 'valueChange',
						data: null,
					});
				}
			}
		}
	}
};

/**
 * @description 失去焦点
 */
const onBlur = ($event: any) => {
	if (!props.multiple) {
		searchVal.value = '';
		isSearch.value = false;
		open.value = false;
	}
	onFocusBlurEmit('blur', $event);
};

/**
 * @description 聚焦
 */
const onFocus = ($event: any) => {
	if (!isSearch.value) {
		searchVal.value = '';
		isSearch.value = true;
		open.value = true;
	}
	onFocusBlurEmit('focus', $event);
};

/**
 * @description 处理下拉显示改变
 * @param open 打开状态
 */
const handleVisibleChange = (open: boolean) => {
    if (open) {
        onSearch('');
    }
}

/**
 * @description 自动填充搜索
 * @param value 搜索值
 */
const onSearch = (value: string) => {
	searchVal.value = value;
	let _navContext = deepCopy(navContext);
	let _navViewParam = deepCopy(navViewParam);
	const _data = computedNavData(
		props.data,
		_navContext,
		_navViewParam,
		props.localParam
	);
    Object.assign(_navViewParam, _data, { query: searchVal.value, size: 1000 });
	if (props.sort) {
		Object.assign(_navViewParam, { sort: props.sort });
	}
	let requestException: string = App.ts(
		'common.generic.requestexception',
		'请求异常'
	);
	if (!props.acParams) {
		console.warn(App.ts('common.generic.miss', '参数不存在'));
	} else {
		const { serviceName, interfaceName } = props.acParams;
		const { deKeyField, deCodeName } = props;
        searchEntityData(
            serviceName,
            interfaceName,
            _navContext,
            _navViewParam,
            deKeyField,
            deCodeName
        )
        .then((response: any) => {
            if (!response) {
                console.warn(App.ts('common.generic.loadfail', '加载数据失败'));
                return;
            } else {
                if (props.isAC && !props.isDropdown && response.length == 0) {
                    items.value = [{ noData: true }];
                } else {
                    items.value = [...response];
                }
            }
        })
        .catch((error: any) => {
            if (props.isAC && !props.isDropdown) {
                items.value = [{ noData: true }];
            } else {
                items.value = [];
            }
            console.warn(error && error.message ? error.message : requestException);
        });
	}
};

/**
 * @description 自动填充选中
 * @param select 选中数据
 */
const onSelect = (select: any) => {
	const selectItem = items.value.find((item: IParam) =>
		Object.is(item[deKeyField], select)
	);
	switchAppAc();
	isSearch.value = false;
	autoComRef.value.blur();
	searchVal.value = '';
    let value: any = null;
    let valueItem: any = null;
    if (selectItem) {
        if (valueType == 'OBJECT') {
            value = handleObjectParams(selectItem);
        } else {
            value = selectItem[deMajorField];
        }
        valueItem = selectItem[deKeyField];
    }
	emit('component-action', {
		name: `${props.name}`,
		action: 'valueChange',
		data: value,
	});
	if (props.valueItem) {
		emit('component-action', {
			name: props.valueItem,
			action: 'valueChange',
			data: valueItem,
		});
	}
	fillPickUpData(selectItem);
};

/**
 * @description 处理值改变
 * @param selects 选中数据
 */
const onChange = (selects: any, dateString: any) => {
	isSearch.value = false;
    const data: IParam[] = [];
	if (props.multiple) {
		selects.forEach((value: string) => {
			const select = items.value.find((_item: IParam) =>
				Object.is(_item[deKeyField], value)
			);
            if (select) {
                data.push(select)
            }
		});
	} else {
		let select = items.value.find((_item: IParam) => {
			return Object.is(_item[deKeyField], selects);
		});
        data.push(select)
	}
    handleEditorEmit(data);
};

/**
 * @description 处理对象类型参数
 * @param select 选中数据
 */
const handleObjectParams = (select: IParam): IParam => {
    const object: IParam = {
        [deMajorField]: select[deMajorField],
        [deKeyField]: select[deKeyField]
    };
    if (objectValueField) {
        Object.assign(object, {
            [objectValueField]: deepCopy(select)
        })
    }
    return object
}

/**
 * @description 切换下拉显示
 */
const switchAppAc = () => {
	open.value = !open.value;
};

/**
 * @description 清空
 */
const clear = (event: any) => {
	event.stopPropagation();
	event.preventDefault();
    if (props.valueItem) {
		emit('component-action', {
			name: props.valueItem,
			action: 'valueChange',
			data: null,
		});
	}
	emit('component-action', {
		name: `${props.name}`,
		action: 'valueChange',
		data: null,
	});
};

/**
 * @description 处理pickupView值改变
 * @param data 选中数据
 */
const handlePickUpViewValueChange = (data: IParam[]): any => {
    handleEditorEmit(data);
    if (dataPicker.value) {
        dataPicker.value.focus();
        dataPicker.value.blur();
    }
};

/**
 * @description 处理编辑器抛值
 * @param data 选中数据
 */
const handleEditorEmit = (data: IParam[]) => {
    let value: any = null;
	if (props.multiple) {
		let selects: any[] = [];
		data.forEach((item: any, i: number) => {
			const index = items.value.findIndex((_item: any) =>
				Object.is(item[deKeyField], _item[deKeyField])
			);
			if (index < 0) {
				items.value.push(item);
			}
            let selected: any;
            if (valueType == 'OBJECTS') {
                selected = handleObjectParams(item);
            } else {
                // SIMPLE (有objectIdField的情况为搜索表单使用时特殊情况)
                if (objectIdField) {
                    selected = item[objectIdField];
                } else {
                    selected = {
                        [deMajorField]: item[deMajorField],
                        [deKeyField]: item[deKeyField]
                    }
                }
            }
			selects.push(selected);
		});
        if (selects.length > 0) {
            if (valueType == 'OBJECTS') {
                value = selects;
            } else {
                value = objectIdField ? selects.join(valueSeparator ? valueSeparator : ',') : JSON.stringify(selects)
            }
        } else {
            value = null;
        }
		emit('component-action', {
			name: `${props.name}`,
			action: 'valueChange',
			data: value,
		});
	} else {
        let valueItem: any = null;
        const item = data[0];
        if (item) {
            if (valueType == 'OBJECT') {
                value = handleObjectParams(item);
            } else {
                value = item[deMajorField];
            }
            valueItem = item[deKeyField];
        }
        if (props.valueItem) {
			emit('component-action', {
				name: props.valueItem,
				action: 'valueChange',
				data: valueItem,
			});
		}
		emit('component-action', {
			name: `${props.name}`,
			action: 'valueChange',
			data: value,
		});
	}
}

/**
 * @description 打开链接视图
 */
const openLinkView = (event: any): void => {
	event.preventDefault();
	event.stopPropagation();
	if (
		!props.data ||
		!props.valueItem ||
		!props.data.hasOwnProperty(props.valueItem)
	) {
		const formdataexception = App.ts(
			'common.datapicker.formdataexception',
			'表单数据异常！'
		);
		const valueitemexception = App.ts(
			'common.datapicker.valueitemexception',
			'值项异常'
		);
		if (!props.data) {
			console.error(formdataexception);
		} else {
			console.error(valueitemexception);
		}
		return;
	}
	if (!props.linkView) {
        App.getNotificationHelper().error(
            App.ts('common.generic.error'),
            App.ts('common.datapicker.nolinkview')
        )
		return;
	}
	// 公共参数处理
	let data: any = {
		param: {},
		context: {},
	};
	Object.assign(data.param, navViewParam);
	Object.assign(data.context, navContext);

	// 参数处理
	let _context = data.context;
	let _param = data.param;
    if (props.data[props.valueItem]) {
        Object.assign(_context, { [deKeyField]: props.data[props.valueItem] });
    }

	const view = App.getAppViewConfig()?.[props.linkView];
	App.getOpenViewHelper().openPage(view, _context, _param);
};

/**
 * @description 打开选择视图
 */
const openView = async (event: any) => {
	event.preventDefault();
	event.stopPropagation();
	if (props.disabled) {
		return;
	}
	if (!props.pickUpView) {
        App.getNotificationHelper().error(
            App.ts('common.generic.error'),
            App.ts('common.datapicker.nopickupview')
        )
		return;
	}
	const view = App.getAppViewConfig()?.[props.pickUpView];
	if (!view) {
		return;
	}
	const params: IParam = {};
	const tempViewParams = deepCopy(navViewParam);
	//多选
	if (props.multiple) {
		let selectedData: IParam[] = [];
		try {
            if (props.value) {
                let _items: any[] = [];
                if (valueType == 'OBJECTS') {
                    _items = (props.value as any)
                } else {
                    _items = objectIdField ? (props.value as string).split(valueSeparator ? valueSeparator : ',') : JSON.parse(props.value as any)
                }
                _items.forEach((_item: any) => {
                    let tempItem: any;
                    if (valueType !== 'OBJECTS' && objectIdField) {
                        tempItem = items.value.find((item: IParam) => item[deKeyField] == _item);
                    } else {
                        tempItem = _item;
                    }
                    if (tempItem) {
                        selectedData.push({
                            srfkey: tempItem[deKeyField],
                            srfmajortext: tempItem[deMajorField]
                        })
                    }
                })
            }
		} catch (error) {
			selectedData = [];
		}
		Object.assign(tempViewParams, { selectedData: selectedData });
	} else {
		const selectedData: IParam = {};
		if (
			props.data &&
			props.valueItem &&
			isExistAndNotEmpty(props.data[props.valueItem])
		) {
			Object.assign(selectedData, { srfkey: props.data[props.valueItem] });
		}
		if (isExistAndNotEmpty(`${props.value}`)) {
			Object.assign(selectedData, { srfmajortext: valueType == 'OBJECT' ? (props.value as any)[deMajorField] : props.value });
		}
		Object.assign(tempViewParams, { selectedData: [selectedData] });
	}
	if (
		!Object.is(view.openMode, 'POPOVER') &&
		!Object.is(view.openMode, 'DRAWER')
	) {
		Object.assign(params, { openMode: 'POPUPMODAL' });
	}
	const result = await App.getOpenViewHelper().openModal(
		view,
		deepCopy(navContext),
		tempViewParams
	);
	if (result && result.ok) {
		handlePickUpViewValueChange(result.data as Array<any>);
	}
};

/**
 * 抛出聚焦,失去焦点事件
 */
const onFocusBlurEmit = (type: 'blur' | 'focus', $event: any) => {
	if (type == 'blur') {
		emit('component-action', {
			name: `${props.name}`,
			action: 'editorBlur',
			data: $event,
		});
	} else if (type == 'focus') {
		emit('component-action', {
			name: `${props.name}`,
			action: 'editorFocus',
			data: $event,
		});
	}
}
</script>
